#include "ProcessSound.h"
//
////#include "Views.h"
////#include "Fft.h"
#include "WaveIn.h"
#include "WinEx.h"
#include <sstream>
#include <cassert>
#include "Playground.h"
#include <fftw3.h>
//
ProcessSound::ProcessSound (wxGauge *newGauge)
:
	_source (16), // num of buffers
  _fftPoints (0),
	_changed (false)
{
  theGauge = newGauge;
	_event.Block ();
	_thread.Resume ();
//  in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * _outBuf.size());
//  out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * _outBuf.size());
//  p = fftw_plan_dft_1d(_outBuf.size(), in, out, FFTW_FORWARD, FFTW_ESTIMATE);
}

void ProcessSound::SetFormat (
    unsigned samplesPerBuf,
    unsigned samplesPerSec,
    unsigned fftPoints,
    unsigned bitsPerSample) throw ()
{
	Win::Lock lock (_critSect);
	if (bitsPerSample == (unsigned)_format.BitsPerSample () &&
		samplesPerSec == (unsigned)_format.SamplesPerSec () &&
		fftPoints == _fftPoints &&
		samplesPerBuf == _samplesPerBuf)
	{
		return;
	}
	_changed = true;
	_samplesPerBuf = samplesPerBuf;
	_format.nSamplesPerSec = samplesPerSec;
	_fftPoints = fftPoints;
	_format.wBitsPerSample = bitsPerSample;
	_format.nChannels = 1;
}

void ProcessSound::ReInit () throw () {
    Win::Lock lock (_critSect);
	if (!_changed)
		return;
	_changed = false;

    bool wasStarted = false;
	if (_device.get () != 0)
		wasStarted = _device->IsStarted ();

	try {

			_device = std::auto_ptr<Wave::AsyncDevice> (new Wave::InDevice (_format));
		_format = _device->GetFormat ();

		//_fftTransformer = std::auto_ptr<Fft> (new Fft (_fftPoints, _format.SamplesPerSec ()));
		_device->Open (_event);
		_source.PlugInDevice (_device.get (), _samplesPerBuf);
		if (wasStarted)
			_device->Start ();
		else
			_device->Stop ();
    }
    catch (Win::Exception e) {
      //TODO const char* to const WCHAR*
//		std::ostringstream buf;
//		buf << e.GetMessage () << ", Error " << std::hex << e.GetError ();
//		::MessageBox (0, buf.str ().c_str (), "Exception", MB_ICONEXCLAMATION | MB_OK);
    }
    catch (...) {
      //TODO const char* to const WCHAR*
        //::MessageBox (0, "Unknown", "Exception", MB_ICONEXCLAMATION | MB_OK);
    }
}

ProcessSound::~ProcessSound () {
//  fftw_destroy_plan(p);
//  fftw_free(in);
//  fftw_free(out);
}

void ProcessSound::Run () {
	try	{
		for (;;) {
			_event.Wait ();
			if (_isDying)
				return;

			Win::Lock lock (_critSect);
			if (_source.IsDataReady ())
				LokWaveInData ();
		}
	}
	catch (Win::Exception & e) {
		std::ostringstream buf;
		buf << e.GetMessage () << ", Error " << std::hex << e.GetError ();
		//TODO const char* to const WCHAR*
		//::MessageBox (0, buf.str ().c_str (), "Exception", MB_ICONEXCLAMATION | MB_OK);
	}
	catch (...) {
	  //TODO const char* to const WCHAR*
		//::MessageBox (0, "Unknown", "Exception", MB_ICONEXCLAMATION | MB_OK);
	}
}

void ProcessSound::FlushThread () {
    _event.Release ();
}

bool ProcessSound::Start () throw () {
	bool success = false;
	try {
		Win::Lock lock (_critSect);
		_device->Start ();
		success = true;
	}
	catch (Win::Exception e) {
        //char buf [50];
		// revisit: use strstream
	  //TODO const char* to const WCHAR*
//        wsprintf ( buf, "%s, Error %d", e.GetMessage(), e.GetError() );
//        ::MessageBox (0, buf, "Exception", MB_ICONEXCLAMATION | MB_OK);
    }
    catch (...) {

	  //TODO const char* to const WCHAR*
//        ::MessageBox (0, "Unknown", "Exception", MB_ICONEXCLAMATION | MB_OK);
    }
	return success;
}

void ProcessSound::Stop () {
    Win::Lock lock (_critSect);
    _device->Stop ();
}

void ProcessSound::LokWaveInData () {
	_source.GetData (_outBuf);
	unsigned int n = _outBuf.size();
	double max = 0;
  for(unsigned int i=0; i<n; i++) {
    if(_outBuf[i]>=0)
      theGauge->SetValue(_outBuf[i]/50);
    in[i][0]=(double)_outBuf[i];
    in[i][1]=(double)_outBuf[i];
  }
    fftw_execute(p);

    for(unsigned int i=0; i<n;i++) {
      if(out[i][0]>max)
        max=out[i][0];
    }

    //_fftTransformer->Transform (_outBuf);
//    _viewFreq.Update (*_fftTransformer);
//    _viewWave.Update (_outBuf);
}

